using EnvDTE;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AvaVSExt.Helpers
{
    public enum ItemType
    {
        Unknown = 0, File, Folder
    }

    public class SelectionItemInfo : ItemInfo
    {
        public int SelectionStartIndex { get; set; }
        public int SelectionEndIndex { get; set; }

        public string SelectionText { get; set; }


        public SelectionItemInfo()
        {

        }

        public SelectionItemInfo(string projectPath, string itemPath) : base(projectPath, itemPath)
        {

        }

        public void DeleteSelection()
        {
            VSHelper.DeleteSelection();
        }

        public void UpdateSelection(string newCode)
        {
            VSHelper.UpdateSelection(newCode);
        }

    }

    public class ItemInfo
    {
        public string ProjectFullPath { get; set; }
        public string ProjectName { get; set; }
        public string ProjectDirPath { get; set; }
        public string ItemFullPath { get; set; }
        public string ItemShortPath { get; set; }
        public ItemType ItemType { get; set; }
        public ItemInfo()
        {

        }

        public ItemInfo(string projectPath, string itemPath)
        {
            ProjectFullPath = projectPath;
            ProjectName = Path.GetFileNameWithoutExtension(projectPath);
            ProjectDirPath = Path.GetDirectoryName(projectPath);
            ItemFullPath = itemPath;
            ItemShortPath = itemPath.Substring(ProjectDirPath.Length).Trim('\\').Trim('/');

            if (File.Exists(ItemFullPath))
            {
                ItemType = ItemType.File;
            }
            else if (Directory.Exists(ItemFullPath))
            {
                ItemType = ItemType.Folder;
            }
        }

        public override string ToString()
        {
            return $"{ProjectDirPath} {ItemShortPath}";
        }

        public string GetNamespaceName()
        {
            if (ItemType != ItemType.Folder) throw new Exception();

            var str = ProjectName + "." + ItemShortPath.Replace('\\', '.').Replace('/', '.').Trim('.');

            return str;
        }

        public string GetNamespaceName(string rootName)
        {
            if (string.IsNullOrWhiteSpace(rootName)) return GetNamespaceName();
            if (ItemType != ItemType.Folder) throw new Exception();

            var str = rootName + "." + ItemShortPath.Replace('\\', '.').Replace('/', '.').Trim('.');

            return str;
        }

    }

    public static class VSHelper
    {
        public static ItemInfo GetSelectedItemInfoInSolutionExplorer()
        {
            var DTE = GetDTE();

            var toolWindow = DTE.ToolWindows;

            var solutionExplorer = toolWindow.SolutionExplorer;

            var selectedItems = (solutionExplorer.SelectedItems as IEnumerable).OfType<UIHierarchyItem>().Select(i => i.Object).OfType<ProjectItem>();
            var selectedItem = selectedItems.FirstOrDefault();

            if (selectedItem == null) return null;

            var project = selectedItem.ContainingProject;
            var projectFullName = project.FullName;
            var itemPath = selectedItem.FileNames[0];
            return new ItemInfo(projectFullName, itemPath);
        }

        public static ItemInfo GetSelectedItemInfoInSolutionExplorerCs()
        {
            var DTE = GetDTE();

            var toolWindow = DTE.ToolWindows;

            var solutionExplorer = toolWindow.SolutionExplorer;

            var selectedItems = (solutionExplorer.SelectedItems as IEnumerable).OfType<UIHierarchyItem>().Select(i => i.Object).OfType<ProjectItem>();
            var selectedItem = selectedItems.FirstOrDefault();

            if (selectedItem == null) return null;

            var project = selectedItem.ContainingProject;
            var projectFullName = project.FullName;
            var itemPath = selectedItem.FileNames[0];

            if (itemPath.EndsWith("axaml") || itemPath.EndsWith("xaml"))
            {
                var codeBehindPath = itemPath + ".cs";
                if (File.Exists(codeBehindPath)) return new ItemInfo(projectFullName, codeBehindPath);
            }

            return new ItemInfo(projectFullName, itemPath);
        }

        public static ItemInfo GetCurrentEditItemInfo()
        {
            EnvDTE80.DTE2 DTE = GetDTE();
            var projectItem = DTE.ActiveDocument.ProjectItem;
            var project = projectItem.ContainingProject;
            var projectFullName = project.FullName;
            var itemPath = projectItem.FileNames[0];
            return new ItemInfo(projectFullName, itemPath);
        }

        public static SelectionItemInfo GetSelectionItemInfo()
        {
            EnvDTE80.DTE2 DTE = GetDTE();
            var projectItem = DTE.ActiveDocument.ProjectItem;
            var project = projectItem.ContainingProject;
            var projectFullName = project.FullName;
            var itemPath = projectItem.FileNames[0];
            var selelction = DTE.ActiveDocument.Selection as TextSelection;
            var selectionStartIndex = selelction.ActivePoint.VirtualCharOffset;

            projectItem.Save();

            return new SelectionItemInfo(projectFullName, itemPath)
            {
                SelectionText = selelction.Text
            };
        }

        public static void DeleteSelection()
        {
            EnvDTE80.DTE2 DTE = GetDTE();
            var projectItem = DTE.ActiveDocument.ProjectItem;
            var project = projectItem.ContainingProject;
            var projectFullName = project.FullName;
            var itemPath = projectItem.FileNames[0];
            var selelction = DTE.ActiveDocument.Selection as TextSelection;

            selelction.Delete();
        }

        public static void UpdateSelection(string newCode)
        {
            EnvDTE80.DTE2 DTE = GetDTE();
            var projectItem = DTE.ActiveDocument.ProjectItem;
            var project = projectItem.ContainingProject;
            var projectFullName = project.FullName;
            var itemPath = projectItem.FileNames[0];
            var selelction = DTE.ActiveDocument.Selection as TextSelection;
            selelction.Text = newCode;
        }

        public static string GetSlnName()
        {
            EnvDTE80.DTE2 DTE = GetDTE();
            var solution = DTE.Solution;
            return solution.FileName;
        }

        public static string GetSlnDir()
        {
            var slnName = GetSlnName();
            return Path.GetDirectoryName(slnName);
        }

        public class SelectionLineInfo
        {
            public string Text { get; set; }
            public int CursorIndex { get; set; } = 0;
        }
        public static SelectionLineInfo GetCurrentSelectLineText()
        {
            EnvDTE80.DTE2 DTE = GetDTE();
            var document = DTE.ActiveDocument;
            var projectItem = document.ProjectItem;
            var project = projectItem.ContainingProject;
            var projectFullName = project.FullName;
            var itemPath = projectItem.FileNames[0];

            if (itemPath.EndsWith("xaml") == false) return null;

            var textDocument = document as TextDocument;
            var selelction = DTE.ActiveDocument.Selection as TextSelection;

            var activePoint = selelction.ActivePoint;
            var activeLine = activePoint.Line;
            var text = activePoint.CreateEditPoint().GetLines(activeLine, activeLine + 1);

            return new SelectionLineInfo()
            {
                CursorIndex = activePoint.LineCharOffset - 1,
                Text = text
            };
        }

        private static EnvDTE80.DTE2 GetDTE()
        {
            return Marshal.GetActiveObject("VisualStudio.DTE") as EnvDTE80.DTE2;
        }

        public static void Open(string filePath)
        {
            var dte = GetDTE();
            dte.Documents.Open(filePath);
        }
    }
}
